package com.opennews.openplatform.familyexpenseapi.controller

import com.opennews.openplatform.familyexpenseapi.common.constant.IncomeExpenseType
import com.opennews.openplatform.familyexpenseapi.common.constant.PaymentType
import com.opennews.openplatform.familyexpenseapi.service.IncomeExpenseAnalysisService
import com.opennews.openplatform.myspringbootcore.dto.ApiResponse
import com.opennews.openplatform.myspringbootcore.extension.isNullOrBlankOrLiteralNull
import com.opennews.openplatform.myspringbootcore.util.getSuccessResponse
import com.opennews.openplatform.myspringbootmvccore.security.RequestIdentityExtractor
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.MissingServletRequestParameterException
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/income-expense-analysis")
class IncomeExpenseAnalysisController(
    private val incomeExpenseAnalysisService: IncomeExpenseAnalysisService,
    private val requestIdentityExtractor: RequestIdentityExtractor,
) {
    @GetMapping("/query-existing-distinct-years")
    fun queryExistingDistinctYears(): ResponseEntity<ApiResponse<List<Int>>> {
        val accountGroupId = requestIdentityExtractor.getClaims().accountGroupId.asString()
        val result = incomeExpenseAnalysisService.queryExistingDistinctYears(accountGroupId)

        return getSuccessResponse(result)
    }

    @GetMapping("/query-summary-by-existing-years")
    fun querySummaryByExistingYears(): ResponseEntity<ApiResponse<List<Map<String, Any>>>> {
        val accountGroupId = requestIdentityExtractor.getClaims().accountGroupId.asString()
        val years = incomeExpenseAnalysisService.queryExistingDistinctYears(accountGroupId)
        val result = incomeExpenseAnalysisService.queryAnnualSummaryByYears(accountGroupId, years)

        return getSuccessResponse(result)
    }

    @GetMapping("/query-overall-summary")
    fun queryOverallSummary(): ResponseEntity<ApiResponse<Map<String, Map<String, Any>>>> {
        val accountGroupId = requestIdentityExtractor.getClaims().accountGroupId.asString()
        val result = incomeExpenseAnalysisService.queryOverallSummary(accountGroupId)

        return getSuccessResponse(result)
    }

    @GetMapping("/query-annual-monthly-summary")
    fun queryAnnualMonthlySummary(@RequestParam year: Int): ResponseEntity<ApiResponse<Map<String, Any>>> {
        val accountGroupId = requestIdentityExtractor.getClaims().accountGroupId.asString()

        val cashIncomeSummary = incomeExpenseAnalysisService.queryAnnualMonthlySummary(
            accountGroupId, IncomeExpenseType.INCOME, PaymentType.CASH, year
        )

        val cashExpenseSummary = incomeExpenseAnalysisService.queryAnnualMonthlySummary(
            accountGroupId, IncomeExpenseType.EXPENSE, PaymentType.CASH, year
        )

        val creditCardIncomeSummary = incomeExpenseAnalysisService.queryAnnualMonthlySummary(
            accountGroupId, IncomeExpenseType.INCOME, PaymentType.CREDIT_CARD, year
        )

        val creditCardExpenseSummary = incomeExpenseAnalysisService.queryAnnualMonthlySummary(
            accountGroupId, IncomeExpenseType.EXPENSE, PaymentType.CREDIT_CARD, year
        )

        return getSuccessResponse(
            mapOf(
                "cashIncomeSummary" to cashIncomeSummary,
                "cashExpenseSummary" to cashExpenseSummary,
                "creditCardIncomeSummary" to creditCardIncomeSummary,
                "creditCardExpenseSummary" to creditCardExpenseSummary
            )
        )
    }

    @GetMapping("/query-monthly-daily-summary")
    fun queryMonthlyDailySummary(
        @RequestParam year: Int,
        @RequestParam month: Int,
    ): ResponseEntity<ApiResponse<Map<String, Any>>> {
        val accountGroupId = requestIdentityExtractor.getClaims().accountGroupId.asString()

        val cashIncomeSummary = incomeExpenseAnalysisService.queryMonthlyDailySummary(
            accountGroupId, IncomeExpenseType.INCOME, PaymentType.CASH, year, month
        )

        val cashExpenseSummary = incomeExpenseAnalysisService.queryMonthlyDailySummary(
            accountGroupId, IncomeExpenseType.EXPENSE, PaymentType.CASH, year, month
        )

        val creditCardIncomeSummary = incomeExpenseAnalysisService.queryMonthlyDailySummary(
            accountGroupId, IncomeExpenseType.INCOME, PaymentType.CREDIT_CARD, year, month
        )

        val creditCardExpenseSummary = incomeExpenseAnalysisService.queryMonthlyDailySummary(
            accountGroupId, IncomeExpenseType.EXPENSE, PaymentType.CREDIT_CARD, year, month
        )

        return getSuccessResponse(
            mapOf(
                "cashIncomeSummary" to cashIncomeSummary,
                "cashExpenseSummary" to cashExpenseSummary,
                "creditCardIncomeSummary" to creditCardIncomeSummary,
                "creditCardExpenseSummary" to creditCardExpenseSummary
            )
        )
    }

    @GetMapping("/query-top-rank-by-account-group")
    fun queryTopRankByAccountGroup(
        @RequestParam type: String,
        @RequestParam paymentType: String,
        @RequestParam(required = false) year: String?,
        @RequestParam(required = false) month: String?,
        @RequestParam pageSize: Int,
        @RequestParam pageIndex: Int,
    ): ResponseEntity<ApiResponse<List<Map<String, Any>>>> {
        val accountGroupId = requestIdentityExtractor.getClaims().accountGroupId.asString()
        val yearValue = validateIntegerValue("year", year)
        val monthValue = validateIntegerValue("month", month)

        val result = incomeExpenseAnalysisService.queryTopRankByAccountGroup(
            accountGroupId, pageSize, pageIndex, type, paymentType, yearValue, monthValue
        )

        return getSuccessResponse(result)
    }

    @GetMapping("/query-summary-by-detail-type")
    fun querySummaryByDetailType(
        @RequestParam type: String,
        @RequestParam paymentType: String,
        @RequestParam(required = false) year: String?,
        @RequestParam(required = false) month: String?,
    ): ResponseEntity<ApiResponse<List<Map<String, Any>>>> {
        val accountGroupId = requestIdentityExtractor.getClaims().accountGroupId.asString()
        val yearValue = validateIntegerValue("year", year)
        val monthValue = validateIntegerValue("month", month)

        val result = if (type == IncomeExpenseType.EXPENSE) {
            incomeExpenseAnalysisService.queryExpenseByDetailType(accountGroupId, paymentType, yearValue, monthValue)
        } else {
            incomeExpenseAnalysisService.queryIncomeByDetailType(accountGroupId, paymentType, yearValue, monthValue)
        }

        return getSuccessResponse(result)
    }

    private fun validateIntegerValue(strName: String, strValue: String?): Int? {
        var integerValue: Int? = null

        // Manually validate the parameter.
        if (strValue?.isNullOrBlankOrLiteralNull() == false) {
            try {
                integerValue = strValue.toInt()
            } catch (e: NumberFormatException) {
                throw MissingServletRequestParameterException(strName, "Invalid $strName format. Must be an integer.")
            }
        }

        return integerValue
    }
}